package yxk.sso;

import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import kd.bos.cache.CacheFactory;
import kd.bos.cache.DistributeSessionlessCache;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.login.thirdauth.UserAuthResult;
import kd.bos.login.thirdauth.UserProperType;
import kd.bos.util.RevProxyUtil;
import kd.bos.util.StringUtils;
import org.eclipse.jetty.server.Request;
import org.jasig.cas.client.authentication.AuthenticationRedirectStrategy;
import org.jasig.cas.client.authentication.DefaultAuthenticationRedirectStrategy;
import yxk.utils.BosUtil;
import yxk.utils.HttpRequestUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author zhouxu
 * @Date 2023/9/12 10:27
 * @Description:用于OA系统SSO
 */

public class SSOAuth implements kd.bos.login.thirdauth.ThirdSSOAuthHandler{

    private static final Log LOG = LogFactory.getLog(SSOAuth.class);


    @Override
    public void callTrdSSOLogin(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String s) {
        AuthenticationRedirectStrategy authenticationRedirectStrategy = new DefaultAuthenticationRedirectStrategy();

        //未登录跳转首页
        String urlContextPath = RevProxyUtil.getURLContextPath(httpServletRequest);
        LOG.info("enter callTrdSSOLogin,url:" + httpServletRequest.getRequestURL().toString());
        String apptype = httpServletRequest.getParameter("apptype");
        try {
            if( apptype == null || !apptype.equals("kingdee_sky")) {
                //拼装字段
                    //获取回调地址
                    DynamicObject result = BosUtil.getConfigUration("FEISHU-REDIRECT");
                    if (result != null) {
                        String redirectUrl = result.getString("nwg5_url");
                        //url += "?redirect_uri=" + URLEncoder.encode(redirectUrl,"UTF-8") + "&app_id=" + nwg5_user;
                        LOG.info("redirect url:" + redirectUrl);
                        authenticationRedirectStrategy.redirect(httpServletRequest, httpServletResponse, redirectUrl);
                        //httpServletResponse.sendRedirect(redirectUrl);
                    }
            }else{
                 String spUrl= urlContextPath+"mobile.html?"+httpServletRequest.getQueryString();
                 LOG.info("===================spUrl" + spUrl);
                authenticationRedirectStrategy.redirect(httpServletRequest,httpServletResponse,urlContextPath+"login-mobile.html"+"?redirect="+ URLEncoder.encode(spUrl,"UTF-8"));
            }
        } catch (IOException e) {
            LOG.error("callTrdSSOLogin failed", e);
            throw new RuntimeException(e);

        }
        LOG.info("leave callTrdSSOLogin,url:" + httpServletRequest.getRequestURL().toString());
    }

    /**
     * OA单点登录对接
     * @return
     */
    private UserAuthResult oaHandler(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
        LOG.info("enter oaHandler getTrdSSOAuth,url:" + httpServletRequest.getRequestURL().toString());
        UserAuthResult userResult = new UserAuthResult();
        userResult.setSucess(false);

        String source = httpServletRequest.getParameter("source");
        String userCode = httpServletRequest.getParameter("usercode");
        String timplate = httpServletRequest.getParameter("timplate");
        LOG.error("SSOAuth.oaHandler.source:{},userCode:{},timplate:{}",source,userCode,timplate);
        long timestampNow = System.currentTimeMillis();
        long diff = (timestampNow - Long.parseLong(timplate))/1000;
        if(diff >= 300){
            LOG.error("sign expired,diff:{},now:{},timplate:{}",diff,timestampNow,timplate);
            return userResult;
        }

        String sign = httpServletRequest.getParameter("sign");
        LOG.error("SSOAuth.oaHandler.sign:{}",sign);
        String key = source + "-" + userCode + "-" + timplate;

        DistributeSessionlessCache cache = CacheFactory.getCommonCacheFactory().getDistributeSessionlessCache("customRegion");
        String value = cache.get(key);
        if(StringUtils.isNotEmpty(value)){
            LOG.error("sign.aleady.in.deny.access:{},value:{}",key,value);
            return userResult;
        }
        //防止key重复访问
        cache.put(key,sign,300);

        LOG.info("oa usercode:" + userCode);

        if(StringUtils.isEmpty(userCode) || StringUtils.isEmpty(timplate)){
            LOG.error("invalid param:userCode:{},timplate {}",userCode,timplate);
            return userResult;
        }

        String md5 = MD5.create().digestHex(source + userCode + timplate);
        md5 = md5.toUpperCase();
        if(!Objects.equals(sign,md5)){
            LOG.error("invalid signature,md5: {},sign:{}",md5,sign);
            return userResult;
        }

        userResult.setUser(userCode);
        userResult.setUserType(UserProperType.WorkerNumber);
        //会检查用户是否成功
        userResult.setSucess(true);

        return userResult;
    }

    /**
     * FS单点登录对接
     * @return
     */
    private UserAuthResult fsHandler(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
        //飞书判断返回的认证结果
        String code = httpServletRequest.getParameter("code");
        LOG.info("enter fsHandler getTrdSSOAuth,url:" + httpServletRequest.getRequestURL().toString() + ",code:" + code);

        UserAuthResult userResult = new UserAuthResult();
        userResult.setSucess(false);

        //String state = httpServletRequest.getParameter("state");
        if(StringUtils.isEmpty(code)){
            //没有code 直接失败
            LOG.info("empty code");
            return userResult;
        }

        //向飞书申请
        String appAccessToken = null;

        //获取USER ACCESS TOKEN
        DynamicObject result = BosUtil.getConfigUration("FEISHU-USERACCESSTOKEN-WEB");
        if(null == result){
            LOG.info("empty result");
            return userResult;
        }

        //获取TOKEN
        String tokenUrl = result.getString("nwg5_tokenurl");
        String nwg5_user = result.getString("nwg5_user");
        String nwg5_pwd = result.getString("nwg5_password");
        Map<String,Object> map = new HashMap<>();
        map.put("app_id",nwg5_user);
        map.put("app_secret",nwg5_pwd);
        String param = JSON.toJSONString(map);
        try {
            String postResult = HttpRequestUtil.getPostResult(tokenUrl,null,param.toString(), "application/json");
           // HttpResponse res = HttpRequest.post(tokenUrl).header("Content-Type", "").body(param).timeout(180000).execute();
            LOG.info("feishu request url:" + tokenUrl);
            if(postResult != null ){
                JSONObject json = JSONObject.parseObject(postResult);
                Integer retCode = json.getInteger("code");
                String msg = json.getString("message");
                appAccessToken = json.getString("app_access_token");
                //Integer expire = json.getInteger("expire");
                if(0 == retCode){
                    LOG.info("feishu token retCode = {},msg = {}",retCode,msg);
                }else{
                    LOG.error("feishu token retCode = {},msg = {}",retCode,msg);
                }
            }else{
                LOG.error("feishu token error = {}",postResult);
            }
        } catch (Exception e) {
            LOG.error("get feishu token failed",e);
            throw new RuntimeException(e);
        }

        if(StringUtils.isEmpty(appAccessToken)){
            LOG.error("empty appAccessToken");
            return userResult;
        }

        String userAccessTokenUrl = result.getString("nwg5_url");

        String userId = null;
        map.clear();
        map.put("grant_type","authorization_code");
        map.put("code",code);
        param = JSON.toJSONString(map);
        try {
            Map<String,String> headers = new HashMap<>();
            appAccessToken = "Bearer " + appAccessToken;
            headers.put("Authorization",appAccessToken);
            //获取到用户信息
            String postResult = HttpRequestUtil.getPostResult(userAccessTokenUrl,headers, param.toString(), "application/json");

            /*HttpResponse res = HttpRequest.post(userAccessTokenUrl).header("Content-Type", "application/json").
                    header("Authorization",appAccessToken).body(param).timeout(180000).execute();*/
            LOG.info("feishu request url:" + userAccessTokenUrl);
            if(postResult != null){
                JSONObject json = JSONObject.parseObject(postResult);
                Integer retCode = json.getInteger("code");
                String msg = json.getString("msg");
                JSONObject data = json.getJSONObject("data");
                if(0 == retCode){
                    //获取到用户ID
                    userId = data.getString("user_id");
                    LOG.info("feishu token retCode = {},msg = {},userId={}",retCode,msg,userId);

                }else{
                    LOG.error("feishu token retCode = {},msg = {}",retCode,msg);
                }
            }else{
                LOG.error("feishu token error = {}",postResult);
            }
        } catch (Exception e) {
            LOG.error("get feishu token failed",e);
            throw new RuntimeException(e);
        }

        if(StringUtils.isEmpty(userId)){
            LOG.error("empty userId");
            return userResult;
        }

        userResult.setUser(userId);
        userResult.setUserType(UserProperType.WorkerNumber);
        //会检查用户是否成功
        userResult.setSucess(true);
        return userResult;
    }

    @Override
    public UserAuthResult getTrdSSOAuth(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        LOG.info("enter getTrdSSOAuth,url:" + httpServletRequest.getRequestURL().toString());
       LOG.info("((Request) httpServletRequest).getOriginalURI():{}", ((Request) httpServletRequest).getOriginalURI());
        UserAuthResult result=new UserAuthResult();
        String apptype = httpServletRequest.getParameter("apptype");
        try {
            if(Objects.equals(apptype, "feishu") || Objects.equals(apptype, "oa")){
                return ssoWorkflow(httpServletRequest,httpServletResponse);
            }
            if(apptype ==null || !apptype.contains("kingdee_sky")) {
                //判断飞书还是OA
                String source = httpServletRequest.getParameter("source");
                if (Objects.equals(source, "OA")) {
                    return oaHandler(httpServletRequest, httpServletResponse);
                } else if (Objects.equals(source, "FS")) {
                    return fsHandler(httpServletRequest, httpServletResponse);
                }
            }else{
                result.setUserType(UserProperType.UserName);
                result.setSucess(false);
            }
            result.setSucess(false);
        }catch (Exception e){
            LOG.error("-------getTrdSSOAuth.e",e);
            e.printStackTrace();
        }
        return result;
    }

    private UserAuthResult ssoWorkflow(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
        UserAuthResult result=new UserAuthResult();
        String userNumber = httpServletRequest.getParameter("userNumber");
        if(userNumber == null){
            result.setSucess(false);
            return result;
        }
        result.setUser(userNumber);
        result.setUserType(UserProperType.WorkerNumber);
        //会检查用户是否成功
        result.setSucess(true);
        return result;
    }

}
